package com.kh.pajx.sop.util.page;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.kh.pajx.sop.base.IBaseDao;
import com.kh.pajx.sop.base.IBaseService;
import com.kh.pajx.sop.domain.PageBean;
import com.opensymphony.xwork2.ActionContext;

/**
 * 拼接查询HQL语句的辅助类，支持多表查询
 * 具体实现方式请参考main方法
 * 目前版本缺陷：
 * 1.暂不支持fetch连接查询
 * 2.无法支持子查询
 * 3.不支持group by 子句
 * @version 2.0
 * @author:	azzcsimp
 * @Createdate:	2014年6月27日 上午10:02:31
 */
public class QueryHelperForManyTable {

	// =======================常量================================
	/** HQL多表查询-内连接 */
	public static final String INNER_JOIN = "INNER JOIN"; // 可简写为 join  使用with关键字(SQL中用on)	

	/** HQL多表查询-左外连接 */
	public static final String LEFT_OUTER_JOIN = "LEFT OUTER JOIN"; // 可简写为 left join ... with...

	/** HQL多表查询-又外连接 */
	public static final String RIGHT_OUTER_JOIN = "RIGHT OUTER JOIN"; // 可简写为 right join ... with...

	/** HQL多表查询-全连接 */
	public static final String FULL_JOIN = "FULL JOIN";

	// =======================变量================================

	/** SELECT子句  (必须) */
	private String selectClause = "";

	/** FROM子句(必须) */
	private String fromClause = "";

	/** With子句 (使用多表联合查询必须，反之可选) */
	private String withClause = "";

	/** Where子句(可选) */
	private String whereClause = "";

	/** Order by子句(可选) */
	private String orderByClause = "";

	/** 用于存放表索引与表别名的map */
	private Map<Integer, String> tableIndexMap = new HashMap<Integer, String>();

	/** 参数列表 */
	private List<Object> parameters = new ArrayList<Object>();
	
	/** in 占位符与参数键值对 */
	private Map<String,List> inMap = new HashMap<String,List>();

	//===========================================================================

	/***
	 * 生成SELECT子句,默认别名为第一个对象的别名
	 * @param column 查询子项(对应数据库的列)
	 * @return this
	 * @author:	azzcsimp
	 * @Createdate:	2014年6月27日 上午9:38:35
	 */
	public QueryHelperForManyTable addColumns(String... column) {
		return addColumns(0, column);
	}

	/***
	 * 生成SELECT子句,并指定表的添加顺序索引 ,索引从0开始
	 * @param tableIndex 当前表的索引 用于获取别名
	 * @param column 查询子项(对应数据库的列)
	 * @return   this
	 * @author:	azzcsimp
	 * @Createdate:	2014年6月27日 上午9:38:35
	 */
	public QueryHelperForManyTable addColumns(int tableIndex, String... column) {
		if (selectClause.length() == 0) {
			selectClause = "SELECT ";
		}

		if (column.length > 0) {
			selectClause += ",";
		} else {
			selectClause += ((selectClause.length() > 7) ? "," : "")
					+ tableIndexMap.get(tableIndex);
		}

		// 拼接SELECT子句
		for (int i = 0; i < column.length; i++) {
			selectClause = selectClause + tableIndexMap.get(tableIndex) + "."
					+ column[i] + ((column.length - 1 - i) != 0 ? "," : "");
		}

		return this;
	}
	
	/**
	 * 添加两属性相等where条件
	 * @param firstTableIndex 两对象关联中第一个对象(表)添加的索引值 
	 * @param firstColumnName 两对象关联中第一个对象(表)的属性(列)
	 * @param secondTableIndex 两对象关联中第二个对象(表)添加的索引值 
	 * @param secondColumnName 两对象关联中第二个对象(表)的属性(列)
	 * @return   
	 * @author:	azzcsimp
	 * @Createdate:	2014年6月30日 下午5:04:37
	 */
	public QueryHelperForManyTable addColumns(int firstTableIndex,
			String firstColumnName, int secondTableIndex,
			String secondColumnName) {
		if (whereClause.length() == 0) {
			whereClause += " WHERE ";
		} else {
			whereClause += " AND ";
		}
		whereClause += tableIndexMap.get(firstTableIndex) + "." + firstColumnName
				+ "=" + tableIndexMap.get(secondTableIndex) + "."
				+ secondColumnName;
		return this;
	}

	/**
	 * 生成FROM子句
	 * @param clazz 查询对象
	 * @param alias 别名
	 * @author: azzcsimp
	 * @Createdate: 2014年6月12日 下午3:58:01
	 */
	public QueryHelperForManyTable(Class clazz, String alias) {
		fromClause = " FROM " + clazz.getSimpleName() + " " + alias;
		tableIndexMap.put(0, alias);
	}

	/**
	 * 添加多表 并记录索引, 没使用一次索引加1
	 * @param clazz 查询对象
	 * @param alias 别名
	 * @return this
	 * @author:	azzcsimp
	 * @Createdate:	2014年6月27日 上午10:08:39
	 */
	public QueryHelperForManyTable addTable(Class clazz, String alias) {
		fromClause += "," + clazz.getSimpleName() + " " + alias;
		tableIndexMap.put(tableIndexMap.size(), alias);
		return this;
	}

	/**
	 * 添加多表，同时指定该表的联合查询方式
	 * @param clazz 查询对象
	 * @param alias 别名
	 * @param joinType 连接类型  使用本类常量
	 * @return   this
	 * @author:	azzcsimp
	 * @Createdate:	2014年6月27日 上午10:14:57
	 */
	public QueryHelperForManyTable addTable(Class clazz, String alias,
			String joinType) {
		fromClause += " " + joinType + " " + clazz.getSimpleName() + " "
				+ alias;
		tableIndexMap.put(tableIndexMap.size(), alias);
		return this;
	}

	/**
	 * 生成on子句  用于联合查询
	 * @param firstTableIndex 两对象关联中第一个对象(表)添加的索引值 
	 * @param firstColumnName 两对象关联中第一个对象(表)的属性(列)
	 * @param secondTableIndex 两对象关联中第二个对象(表)添加的索引值 
	 * @param secondColumnName 两对象关联中第二个对象(表)的属性(列)
	 * @return   this
	 * @author:	azzcsimp
	 * @Createdate:	2014年6月27日 上午11:17:53
	 */
	public QueryHelperForManyTable addWith(int firstTableIndex,
			String firstColumnName, int secondTableIndex,
			String secondColumnName) {
		if (withClause.length() == 0) {
			withClause += " WITH ";
		} else {
			withClause += " AND ";
		}
		withClause += tableIndexMap.get(firstTableIndex) + "." + firstColumnName
				+ "=" + tableIndexMap.get(secondTableIndex) + "."
				+ secondColumnName;
		return this;
	}

	/**
	 * 拼接Where子句
	 * 在实际使用中可能出现多种情况，如下
	 * 	-addCondition(t.id=?", "1");-普通应用模式
	 * 	-addCondition("t.id BETWEEN ? AND ?","1","3")-需要多个参数模式
	 * 	-addCondition(t.parent IS NULL) -不需要参数模式
	 * 综上 使用变长数组来实现
	 * @param condition 条件信息
	 * @param params 参数
	 * @return   this
	 * @author:	azzcsimp
	 * @Createdate:	2014年6月20日 下午4:25:05
	 */
	public QueryHelperForManyTable addCondition(String condition,
			Object... params) {
		return addCondition(0, condition, params);
	}

	/**
	 * 拼接Where子句
	 * 在实际使用中可能出现多种情况，如下
	 * 	-addCondition(t.id=?", "1");-普通应用模式
	 * 	-addCondition("t.id BETWEEN ? AND ?","1","3")-需要多个参数模式
	 * 	-addCondition(t.parent IS NULL) -不需要参数模式
	 * 综上 使用变长数组来实现
	 * @param tableIndex 当前表的索引 用于获取别名
	 * @param condition
	 * @param params 参数
	 * @return   
	 * @author:	azzcsimp
	 * @Createdate:	2014年6月20日 下午4:25:05
	 */
	public QueryHelperForManyTable addCondition(int tableIndex,
			String condition, Object... params) {
		// 拼接
		if (whereClause.length() == 0) {
			whereClause = " WHERE " + tableIndexMap.get(tableIndex) + "."
					+ condition;
		} else {
			whereClause += " AND " + tableIndexMap.get(tableIndex) + "."
					+ condition;
		}

		// 保存参数
		if (params != null && params.length > 0) {
			for (Object obj : params) {
				parameters.add(obj);
			}
		}
		return this;
	}

	public QueryHelperForManyTable addCondition2(String condition, Object... params) {
		// 拼接
		if (whereClause.length() == 0) {
			whereClause = " WHERE " +  condition;
		} else {
			whereClause += " AND " +  condition;
		}
		
		// 保存参数
		if (params != null && params.length > 0) {
			for (Object obj : params) {
				parameters.add(obj);
			}
		}
		return this;
	}
	
	/**
	 * 如果第一个参数为true，则拼接Where子句
	 * 
	 * @param append 是否添加条件信息
	 * @param condition 条件
	 * @param params 参数
	 */
	public QueryHelperForManyTable addCondition(boolean append,
			String condition, Object... params) {
		return addCondition(append, 0, condition, params);
	}

	/**
	 * 如果第一个参数为true，则拼接Where子句
	 * 
	 * @param append 是否添加当前条件
	 * @param tableIndex 当前表的索引 用于获取别名
	 * @param condition 条件信息
	 * @param params 参数
	 */
	public QueryHelperForManyTable addCondition(boolean append, int tableIndex,
			String condition, Object... params) {
		if (append) {
			addCondition(tableIndex, condition, params);
		}
		return this;
	}
	
	public QueryHelperForManyTable addCondition(boolean append,boolean isIndex,String condition, Object... params){
		if(append){
			if(isIndex){
				addCondition(0, condition, params);
			}else{
				addCondition2(condition, params);
			}
		}
		return this;
	}
	
	public QueryHelperForManyTable addConditionWithIn(int tableIndex,String columnName,String sign, List list){
		// 拼接
		if (whereClause.length() == 0) {
			whereClause = " WHERE " + tableIndexMap.get(tableIndex) + "."
					+ columnName+ " in (:"+ sign +") ";
		} else {
			whereClause += " AND " + tableIndexMap.get(tableIndex) + "."
					+ columnName+ " in (:"+ sign +") ";
		}

		// 保存参数
		if (list != null ) {
			inMap.put(sign, list);
		}
		return this;
	}
	
	public QueryHelperForManyTable addConditionWithIn(boolean append,int tableIndex,String columnName,String sign, List list){
		if(append){
			addConditionWithIn(tableIndex, columnName,sign, list);
		} 
		return this;
	}
	
	public QueryHelperForManyTable addConditionWithIn(boolean append,int tableIndex,String columnName, List list){
		if(append){
			addConditionWithIn(tableIndex, columnName, list);
		} 
		return this;
	}
	
	public QueryHelperForManyTable addConditionWithIn(int tableIndex,String columnName, List list){
		return addConditionWithIn(tableIndex, columnName,columnName, list);
	}
	

	/**
	 * 拼接OrderBy子句
	 * 
	 * @param propertyName
	 *            属性名
	 * @param isAsc
	 *            true表示升序，false表示降序
	 */
	public QueryHelperForManyTable addOrderProperty(String propertyName,
			boolean isAsc) {
		return addOrderProperty(0,propertyName,isAsc);
	}

	/**
	 * 拼接OrderBy子句
	 * @param tableIndex 当前表的索引 用于获取别名
	 * @param propertyName
	 *            属性名
	 * @param isAsc
	 *            true表示升序，false表示降序
	 */
	public QueryHelperForManyTable addOrderProperty(int tableIndex,
			String propertyName, boolean isAsc) {
		if (orderByClause.length() == 0) {
			orderByClause = " ORDER BY " + tableIndexMap.get(tableIndex) + "."
					+ propertyName + (isAsc ? " ASC" : " DESC");
		} else {
			orderByClause += ", " + tableIndexMap.get(tableIndex) + "."
					+ propertyName + (isAsc ? " ASC" : " DESC");
		}
		return this;
	}

	/**
	 * 如果第一个参数为true，则拼接OrderBy子句
	 * 
	 * @param append 是否添加排序规则
	 * @param propertyName 排序属性名
	 * @param asc  true表示升序，false表示降序
	 */
	public QueryHelperForManyTable addOrderProperty(boolean append,
			String propertyName, boolean isAsc) {
		return addOrderProperty(append,0,propertyName,isAsc);
	}

	/**
	 * 如果第一个参数为true，则拼接OrderBy子句
	 * 
	 * @param append 是否添加排序规则
	 * @param tableIndex 当前表的索引 用于获取别名
	 * @param propertyName 排序属性名
	 * @param asc true表示升序，false表示降序
	 */
	public QueryHelperForManyTable addOrderProperty(boolean append,
			int tableIndex, String propertyName, boolean isAsc) {
		if (append) {
			addOrderProperty(tableIndex, propertyName, isAsc);
		}
		return this;
	}

	/**
	 * 获取生成的用于查询数据列表的HQL语句
	 * @return   
	 * @author:	azzcsimp
	 * @Createdate:	2014年6月26日 下午7:56:14
	 */
	public String getListQueryHql() {
		return selectClause + fromClause + withClause + whereClause
				+ orderByClause;
	}

	/**
	 * 获取生成的用于查询总记录数的HQL语句
	 * @return   
	 * @author:	azzcsimp
	 * @Createdate:	2014年6月26日 下午7:58:16
	 */
	public String getCountQueryHql() {
		return "SELECT COUNT(*)" + fromClause + withClause + whereClause
				+ orderByClause;
	}

	/**
	 * 获取参数列表，与HQL过滤条件中的'?'一一对应
	 * 
	 * @return
	 */
	public List<Object> getParameters() {
		return parameters;
	}
	
	public Map<String,List> getInMap(){
		return inMap;
	}

	/**
	 * 查询分页信息，并放到值栈栈顶
	 * 
	 * @param service
	 * @param pageNum
	 * @param pageSize
	 */
	public void preparePageBean(IBaseDao<?> dao, int pageNum, int pageSize) {
		PageBean pageBean = dao.getPageBean(pageNum, pageSize, this);
		ActionContext.getContext().getValueStack().push(pageBean);
	}

	/**
	 * 封装分页信息，并放到值栈栈顶
	 * 封装具体内容查看PageBean
	 * @param service 业务层方法
	 * @param pageNum 当前页码
	 * @param pageSize 每页显示的数量
	 * @author:	azzcsimp
	 * @Createdate:	2014年6月24日 下午3:07:10
	 */
	public void preparePageBean(IBaseService<?> service, int pageNum,
			int pageSize) {
		PageBean pageBean = service.getPageBean(pageNum, pageSize, this);
		ActionContext.getContext().getValueStack().push(pageBean);
	}

	public static void main(String[] args) {
				// 初始化表信息(至少一张表) 此时Department对应tableIndex为 0， 别名d
				new QueryHelperForManyTable(PageBean.class, "d")  //
		                // 添加第二张表  SysDictionary 对应tableIndex为 1 ， 别名s
						.addTable(PageBean.class, "s")//	       
						// 添加第三张表  SysArea对应tableIndex为2，别名a ,与索引1表的关联关系为 left join 即 SysDictionary left join SysArea 
						//.addTable(SysArea.class, "a",QueryHelperForManyTable.LEFT_OUTER_JOIN) 
						// 添加第四长表 Demo对应tableIndex为3，别名o,
						//.addTable(Demo.class,"o")  // 添加第四张表
						.addColumns()   // 无查询列
						.addColumns("id") //单一查询列
						.addColumns("name", "desc")	//一次添加多个列 要求所有的列都同属于一个对象(表)
						.addColumns(0, "xx")  // 为tableIndex为0的对象添加xx属性  解析结果为  d.xx
						.addColumns(1, "wo", "ca")  // 为tableIndex为1的对象添加wo、ca属性  解析结果为  s.wo,s.ca
						.addWith(0, "dpId", 1, "dcId")// 如果使用addTable(Class,"c",QueryHelperForManyTable.**)时，需指定with
						.addWith(0, "dpName", 1, "dcName") // 如果使用addTable(Class,"c",QueryHelperForManyTable.**)时，需指定with
						.addCondition("name=?", "xxx") // 添加条件
						.addCondition(1,"xname=?" ,"oo") // 为tableIndex为1的对象(表)添加条件信息
						.addOrderProperty("id", true) // 添加排序规则
						.addOrderProperty(1, "id", false) //为tableIndex为1的对象(表)添加排序规则
						.getListQueryHql();

		/*QueryHelperForManyTable xx2 = new QueryHelperForManyTable(Department.class,"d").addColumns(
				 "School").addColumns("xx").addColumns();

		QueryHelperForManyTable xx3 = new QueryHelperForManyTable(Department.class,"d").addColumns(
				 "School", "Student", "Class").addColumns("xx").addColumns().addColumns("xx","oo");
		*/
		
	}
}
